﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using shop.Model;
using System;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading.Tasks;
using CommonTools;
using System.Linq;
using OfficeOpenXml;
using System.Drawing;
using Newtonsoft.Json;
using shop.Bll.cost;
using shp.Web.Controllers.FileServ;
using shop.Web.Common;
using Microsoft.AspNetCore.SignalR;
using shop.Web.hub;

namespace shop.Web.Controllers.api
{

#pragma warning disable CA1416 // 验证平台兼容性


    /// <summary> 退换货的图片管理 </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class RefundRegistController : ControllerBase
    {

        /// <summary> 文件存放目录 </summary>
#if DEBUG
        internal static string _fileDir = @"D:\ruige";
#else
        internal static string _fileDir = @"D:\guantong\webfiles";
#endif

        static RefundRegistController()
        {
            if(!Directory.Exists(_fileDir))
            {
                new DirectoryInfo(_fileDir).Create();
            }
        }

        readonly IFreeSql _sql;

        public RefundRegistController(IFreeSql sql)
        {
            _sql = sql;
        }





        /// <summary> 上传 </summary>
        [HttpPost]
        [RequestSizeLimit(1000_000_000)]
        public async Task<bool> Upload([Required] IFormFile file)
        {

            var filePath = Path.Combine(_fileDir, file.FileName);
            using (var fs = new FileStream(filePath, FileMode.Create))
            {
                await file.CopyToAsync(fs);
                await fs.FlushAsync();
            }

            return true;



            /*
             * 不管用 
             * 
             * 遇到大文件不能上传的问题, 需要修改iis上的配置
            在web.config中加入如下配置：
            代码如下:
            <system.webServer>
                <security>
                    <requestFiltering>
                        <requestLimits maxAllowedContentLength="10485760000"></requestLimits>
                    </requestFiltering>
                </security>
            </system.webServer>
            
            单位是 byte
             * 
             */

        }



        /// <summary> 检查是否存在 </summary>
        [HttpGet]
        public bool IsExists(string name)
        {
            var filePath = Path.Combine(_fileDir, name);
            return System.IO.File.Exists(filePath);
        }


        /// <summary> 下载 </summary>
        [HttpGet]
        public FileStreamResult Download(string fileName)
        {
            var filePath = Path.Combine(_fileDir, fileName.Trim('\\'));

            if (!System.IO.File.Exists(filePath))
            {
#if DEBUG
                return null;
#else
                throw new FileNotFoundException();
#endif
            }

            var fsr = new FileStreamResult(new FileStream(filePath, FileMode.Open), "application/octet-stream");
            fsr.FileDownloadName = Path.GetFileName(fileName);    //指定文件名称
            //fsr.FileDownloadName = fileName;

            return fsr;
        }



        /// <summary> 导出 并带有图片 </summary>
        [HttpPost]
        public async Task<FileStreamResult> Export([FromBody]RefundRegQueryDto pr)
        {
            var begin = pr.Begin.Date;
            var end = pr.End.LastTimeOfDay();

            var list = await DB.FSql.Select<RefundRegist, StockWechat>()
                .LeftJoin((a, b) => a.Stock == b.Stock && b.isdel == false)
                .Where((a, b) => a.Isdel == false)
                .Where((a, b) => a.OccurDate >= begin && a.OccurDate <= end)
                //.WhereIf(pr.IsSendMessage != null, (a, b) => a.IsSendMessage == pr.IsSendMessage)
                .WhereIf(!string.IsNullOrEmpty(pr.Shop), (a, b) => a.Shop == pr.Shop)
                .WhereIf(!string.IsNullOrEmpty(pr.Stock), (a, b) => a.Stock== pr.Stock)
                .WhereIf(!string.IsNullOrEmpty(pr.src_tids), (a, b) => a.src_tids == pr.src_tids)
                .WhereIf(!string.IsNullOrEmpty(pr.platform_goods_id), (a, b) => a.platform_goods_id == pr.platform_goods_id)

                .ToListAsync((a, b) => new
                {
                    a.DocId,
                    a.Number,
                    a.OccurDate,
                    a.Stock,
                    a.spec_no,
                    a.platform_goods_id,
                    a.IsChecked,
                    a.IsSendMessage,
                    a.LogiNo,
                    a.Remarks,
                    a.src_tids,
                    a.Processor,
                    a.Shop,
                    a.RefundFrom,
                    a.Wangwang,
                    a.PayAmount,
                    a.Reason,
                    a.Reason2,
                    a.Reason3,
                    a.PreparedBy,
                    b.WechatGroup,
                    //a.ImageUrls,
                });

            var data = list.Select(a => new
            {
                //a.DocId,
                //选择 = false,
                编号 = a.Number,
                制单人 = a.PreparedBy,
                日期 = a.OccurDate,
                处理人 = a.Processor,
                店铺 = a.Shop,
                订单编号 = a.src_tids,
                产品ID = a.platform_goods_id,
                商家编码 = a.spec_no,
                快递单号 = a.LogiNo,
                金额 = a.PayAmount,
                仓库 = a.Stock,
                详细赔偿原因 = a.Reason,
                详细赔偿原因2 = a.Reason2,
                详细赔偿原因3 = a.Reason3,
                赔偿来源 = a.RefundFrom,
                旺旺号= a.Wangwang,
                备注 = a.Remarks,
                是否已发送消息 = a.IsSendMessage ? "未发送" : "已发送",
                微信群 = a.WechatGroup,
                图片 = string.Empty,
            })
                .ToList();




            var dir = Path.Combine(_fileDir, "temp");

            if (Directory.Exists(dir) == false)
            {
                new DirectoryInfo(dir).Create();
            }

            //var id = string.IsNullOrEmpty(filePath) ? Guid.NewGuid().ToString("N") : jobId;    
            if(string.IsNullOrEmpty(pr.filePath))
            {
                pr.filePath = Path.Combine(dir, "退换货导出_" + Guid.NewGuid().ToString("N") + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx");
            }


            new ExcelExporter()
                .NewSheet("")
                .AddList(data)
                .End(pr.filePath);

            // 图片
            using var _pck = new ExcelPackage(pr.filePath);

            var sht = _pck.Workbook.Worksheets[0];
            int i = 2;
            sht.DefaultRowHeight = 25;
            sht.Columns[20].Width = 15;

            foreach (var item in list)
            {
                //行高
                sht.Rows[i].Height = 50;

                var imgs = await DB.FSql.Select<RefundRegistImage>()
                    .Where(a => a.Isdel == false && a.DocId == item.DocId)
                    .ToListAsync();

                int c = 20; //列

                //
                if (pr.UsePicLink)
                {
                    //插入链接, 
                    foreach (var img in imgs)
                    {
                        if (string.IsNullOrEmpty(img.ImgUlr))
                        {
                            continue;
                        }

                        sht.Cells[i,c].Hyperlink = new Uri("http://frp122.mazh.xyz:7333/api/RefundRegist/Download?fileName=" + img.ImgUlr);
                        sht.Cells[i, c].Style.Border.SetAllBorder(OfficeOpenXml.Style.ExcelBorderStyle.Thin);
                        c++;
                    }

                }
                else
                {
                    foreach (var img in imgs)
                    {
                        if (string.IsNullOrEmpty(img.ImgUlr))
                        {
                            continue;
                        }

                        var imgPath = Path.Combine(_fileDir, img.ImgUlr);
                        if (System.IO.File.Exists(imgPath) == false)
                        {
                            continue;
                        }
                        InsertImage(sht, imgPath, i, c++, false);
                    }
                }

                
                i++;
            }

            await _pck.SaveAsync();

            if(string.IsNullOrEmpty(pr.filePath))
            {
                var fsr = new FileStreamResult(new FileStream(pr.filePath, FileMode.Open), "application/octet-stream");
                fsr.FileDownloadName = Path.GetFileName(pr.filePath);    //指定文件名称

                return fsr;

            }
            else
            {
                return null;
            }
        }


        /// <summary> 生成后台任务, 下载表格 </summary>
        [HttpPost]
        public async Task ExportTask([FromBody] RefundRegQueryDto find, [FromServices] IHubContext<UserJobsHub> hub)
        {
            //后台任务
            var job = new BackgroundJob()
            {
                CreateTime = DateTime.Now,
                FUser = find.FUser,
                UserId= find.UserId,
                JobName = "导出退换报表",
                JobRemarks = JsonConvert.SerializeObject(find),
            };


            var cont = new JobsController(_sql);
            job.JobId = await cont.CreateJob(job);

            //var filePath = Path.Combine(FileTransferController._fileDir, "jobs");
            //if (!Directory.Exists(filePath))
            //{
            //    new DirectoryInfo(filePath).Create();
            //}

            var filePath = Path.Combine(FileTransferController._fileDir, "temp", "导出退换货_" + job.JobId + ".xlsx");  //文件名

            var link = this.HttpContext.Request.Scheme + "://" + this.Request.Host
                      + "/api/FileTransfer/Download?fileName="
                      + filePath.Replace(FileTransferController._fileDir, "").Trim('\\');
            

#pragma warning disable CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
            Task.Run(async () =>
            {

                try
                {
                    find.filePath = filePath;
                    
                    await Export(find);
                    
                    cont.MakeJobDone(job.JobId, false, link, null,hub);

                }
                catch (Exception ex)
                {
                    cont.MakeJobDone(job.JobId, true, null, ex.Message, hub);

                    throw;
                }
            });

#pragma warning restore CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法




        }



        #region MyRegion

        /// <summary>
        /// 插入图片
        /// </summary>
        /// <param name="worksheet"></param>
        /// <param name="imageFile"></param>
        /// <param name="rowNum"></param>
        /// <param name="columnNum"></param>
        /// <param name="autofit"></param>
        private void InsertImage(ExcelWorksheet worksheet, string imageFile, int rowNum, int columnNum, bool autofit)
        {
            //using (var image = Image.FromStream(new MemoryStream(imageBytes)))
            using (var image = Image.FromFile(imageFile))
            {
                var picture = worksheet.Drawings.AddPicture($"image_{DateTime.Now.Ticks}", imageFile);
                //var cell = worksheet.Cells[rowNum, columnNum];
                //int cellColumnWidthInPix = 200; // GetWidthInPixels(cell);
                //int cellRowHeightInPix = 50;    // GetHeightInPixels(cell);
                //int adjustImageWidthInPix = cellColumnWidthInPix;
                //int adjustImageHeightInPix = cellRowHeightInPix;
                //if (autofit)
                //{
                //    //图片尺寸适应单元格
                //    var adjustImageSize = GetAdjustImageSize(image, cellColumnWidthInPix, cellRowHeightInPix);
                //    adjustImageWidthInPix = adjustImageSize.Item1;
                //    adjustImageHeightInPix = adjustImageSize.Item2;
                //}
                //设置为居中显示
                //int columnOffsetPixels = (int)((cellColumnWidthInPix - adjustImageWidthInPix) / 2.0);
                //int rowOffsetPixels = (int)((cellRowHeightInPix - adjustImageHeightInPix) / 2.0);

                //按照高度缩放
                var scale = 55m / image.Height;
                var width = (int)(image.Width * scale); //缩放后的宽度

                //保证宽度
                var w = GetWidthInExcel(width + 4, worksheet.Cells[rowNum, columnNum]);
                if (worksheet.Columns[columnNum].Width <= w ) 
                {
                    worksheet.Columns[columnNum].Width =w;
                }

                picture.SetSize(width, 55);
                //picture.SetSize(scale);
                //picture.SetPosition(rowNum - 1, rowOffsetPixels, columnNum - 1, columnOffsetPixels);

                //picture.AdjustPositionAndSize();
                picture.SetPosition(rowNum - 1,2, columnNum - 1, 2);
            }
        }


        /// <summary>
        /// 获取自适应调整后的图片尺寸
        /// </summary>
        /// <param name="image"></param>
        /// <param name="cellColumnWidthInPix"></param>
        /// <param name="cellRowHeightInPix"></param>
        /// <returns>item1:调整后的图片宽度; item2:调整后的图片高度</returns>
        private static Tuple<int, int> GetAdjustImageSize(Image image, int cellColumnWidthInPix, int cellRowHeightInPix)
        {
            int imageWidthInPix = image.Width;
            int imageHeightInPix = image.Height;

            //调整图片尺寸,适应单元格
            int adjustImageWidthInPix;
            int adjustImageHeightInPix;
            if (imageHeightInPix * cellColumnWidthInPix > imageWidthInPix * cellRowHeightInPix)
            {
                //图片高度固定,宽度自适应
                adjustImageHeightInPix = cellRowHeightInPix;
                double ratio = (1.0) * adjustImageHeightInPix / imageHeightInPix;
                adjustImageWidthInPix = (int)(imageWidthInPix * ratio);
            }
            else
            {
                //图片宽度固定,高度自适应
                adjustImageWidthInPix = cellColumnWidthInPix;
                double ratio = (1.0) * adjustImageWidthInPix / imageWidthInPix;
                adjustImageHeightInPix = (int)(imageHeightInPix * ratio);
            }
            return new Tuple<int, int>(adjustImageWidthInPix, adjustImageHeightInPix);
        }


        //static Lazy<double> _pxBaseline = new Lazy<double>(() => Math.Round(MeasureString("1234567890", font) / 10));


        /// <summary>
        /// 获取单元格的宽度(像素)
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        private static int GetWidthInPixels(ExcelRange cell)
        {
            double columnWidth = cell.Worksheet.Column(cell.Start.Column).Width;
            var font = new Font(cell.Style.Font.Name, cell.Style.Font.Size, FontStyle.Regular);
            double pxBaseline = Math.Round(MeasureString("1234567890", font) / 10);
            return (int)(columnWidth * pxBaseline);
        }


        /// <summary> 通过像素计算单元格宽度 </summary>
        private static int GetWidthInExcel(int pix,  ExcelRange cell)
        {
            var font = new Font(cell.Style.Font.Name, cell.Style.Font.Size, FontStyle.Regular);
            double pxBaseline = Math.Round(MeasureString("1234567890", font) / 10);
            
            return (int)(pix / pxBaseline);
        }




        ///// <summary>
        ///// 获取单元格的高度(像素)
        ///// </summary>
        ///// <param name="cell"></param>
        ///// <returns></returns>
        //private static int GetHeightInPixels(ExcelRange cell)
        //{
        //    double rowHeight = cell.Worksheet.Row(cell.Start.Row).Height;
        //    using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
        //    {
        //        float dpiY = graphics.DpiY;
        //        return (int)(rowHeight * (1.0 / DEFAULT_DPI) * dpiY);
        //    }
        //}

        /// <summary>
        /// MeasureString
        /// </summary>
        /// <param name="s"></param>
        /// <param name="font"></param>
        /// <returns></returns>
        private static float MeasureString(string s, Font font)
        {
            using (var g = Graphics.FromHwnd(IntPtr.Zero))
            {
                g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
                return g.MeasureString(s, font, int.MaxValue, StringFormat.GenericTypographic).Width;
            }
        }



        #endregion

    }

#pragma warning restore CA1416 // 验证平台兼容性

}
